﻿#region Using
using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using JigLibX.Physics;
using JigLibX.Geometry;
using JigLibX.Collision;
using JigLibX.Math;
using Debug;
#endregion Using

namespace LloydGame
{
    public class GameWorld : GameComponent
    {
        #region Class fields
        protected List<GameObject> m_gameObjects;
        protected List<GameObject> m_objectsToRemove;
        protected List<PowerUpObject> m_PowerUpsToSpawn;
        protected List<CoinObject> m_CoinsToSpawn;
        protected List<GameLight> m_gameLights;
        protected List<GameSpawnPoint> m_gameSpawnPoints;
        protected List<GamePlayer> m_remoteGamePlayers;
        protected GamePlayer m_gamePlayer;
        protected Vector3 m_localSpawnPos;
        protected Vector3 m_localSpawnRot;
        protected bool m_gameObjectSelected;

        protected RenderTarget2D m_colorTarget;
        protected RenderTarget2D m_depthTarget;
        protected RenderTarget2D m_normalTarget;

        protected DepthStencilBuffer m_depthStencil;

        protected MotionBlurImageProcessor m_motionBlurProcessor;
        protected SimpleImageProcessor m_simpleImageProcessor;
        protected SSAOImageProcessor m_SSAOProcessor;
        protected BloomImageProcessor m_bloomProcessor;

        protected SparkParticleSystem m_sparkParticleSystem;
        protected StarParticleSystem m_starParticleSystem;
        protected GlowParticleSystem m_glowParticleSystem;
        protected SmokeParticleSystem m_smokeParticleSystem;

        // Debug
        protected bool m_debug;
        protected bool m_wireframe;
        #endregion Class fields

        #region Properties
        public List<CoinObject> CoinsToSpawn
        {
            get
            {
                return m_CoinsToSpawn;
            }
        }
        public List<PowerUpObject> PowerUpsToSpawn
        {
            get
            {
                return m_PowerUpsToSpawn;
            }
        }
        public List<GameObject> gameObjects
        {
            get
            {
                return m_gameObjects;
            }
        }
        public List<GameSpawnPoint> gameSpawnPoints
        {
            get
            {
                return m_gameSpawnPoints;
            }
            set
            {
                m_gameSpawnPoints = value;
            }
        }
        public GamePlayer gamePlayer
        {
            get { return m_gamePlayer; }
        }
        public List<GameObject> objectsToRemove
        {
            get
            {
                return m_objectsToRemove;
            }
        }

        public bool gameObjectedSelected
        {
            get
            {
                return m_gameObjectSelected;
            }
            set
            {
                m_gameObjectSelected = value;
            }
        }

        public GameObject GetObject(Body p_body)
        {
            foreach (GameObject gameObject in m_gameObjects)
            {
                if (gameObject.body == p_body)
                {
                    return gameObject;
                }
            }
            return null;
        }
        public CarObject GetCarObject(Body p_body)
        {
            foreach (CarObject carObject in m_gameObjects)
            {
                if (p_body == carObject.body)
                {
                    return carObject;
                }
            }
            return null;
        }
        public GamePlayer GetRemotePlayer(CarObject p_carObject)
        {
            foreach (GamePlayer remoteGamePlayer in m_remoteGamePlayers)
            {
                if (p_carObject == remoteGamePlayer.carObject)
                {
                    return remoteGamePlayer;
                }
            }
            return null;
        }

        public List<GamePlayer> remotePlayers
        {
            get { return m_remoteGamePlayers; }
        }

        public List<GameLight> gameLights
        {
            get
            {
                return m_gameLights;
            }
        }

        public SparkParticleSystem sparkParticleSystem
        {
            get
            {
                return m_sparkParticleSystem;
            }
        }

        public StarParticleSystem starParticleSystem
        {
            get
            {
                return m_starParticleSystem;
            }
        }

        public GlowParticleSystem glowParticleSystem
        {
            get
            {
                return m_glowParticleSystem;
            }
        }

        public SmokeParticleSystem smokeParticleSystem
        {
            get
            {
                return m_smokeParticleSystem;
            }
        }

        //Returns a GameObject with a matching alias, if no match it returns null.
        public GameObject GetObject(String p_alias)
        {
            foreach (GameObject gameObject in m_gameObjects)
            {
                if (gameObject.alias == p_alias)
                {
                    return gameObject;
                }
            }
            return null;
        }

        public bool isDebug
        {
            get { return m_debug; }
        }
        #endregion Properties

        #region Constructors and Initialization
        // constructor
        public GameWorld(Game p_game, String p_worldFile, bool p_debug, bool p_wireframe) : base(p_game)
        {
            m_debug = p_debug;

            m_colorTarget = new RenderTarget2D(
                p_game.GraphicsDevice,
                p_game.GraphicsDevice.Viewport.Width,
                p_game.GraphicsDevice.Viewport.Height,
                1,
                SurfaceFormat.Color);

            m_depthTarget = new RenderTarget2D(
                p_game.GraphicsDevice,
                p_game.GraphicsDevice.Viewport.Width,
                p_game.GraphicsDevice.Viewport.Height,
                1,
                SurfaceFormat.Single);

            m_normalTarget = new RenderTarget2D(
                p_game.GraphicsDevice,
                p_game.GraphicsDevice.Viewport.Width,
                p_game.GraphicsDevice.Viewport.Height,
                1,
                SurfaceFormat.Color);

            m_depthStencil = new DepthStencilBuffer(
                m_colorTarget.GraphicsDevice,
                m_colorTarget.Width,
                m_colorTarget.Height,
                m_colorTarget.GraphicsDevice.DepthStencilBuffer.Format,
                m_colorTarget.MultiSampleType,
                m_colorTarget.MultiSampleQuality);

            m_motionBlurProcessor = new MotionBlurImageProcessor(p_game,
                p_game.GraphicsDevice.Viewport.Width, p_game.GraphicsDevice.Viewport.Height);

            m_simpleImageProcessor = new SimpleImageProcessor(p_game,
                p_game.GraphicsDevice.Viewport.Width, p_game.GraphicsDevice.Viewport.Height);

            m_SSAOProcessor = new SSAOImageProcessor(p_game,
                p_game.GraphicsDevice.Viewport.Width, p_game.GraphicsDevice.Viewport.Height);

            m_bloomProcessor = new BloomImageProcessor(p_game,
                p_game.GraphicsDevice.Viewport.Width, p_game.GraphicsDevice.Viewport.Height);

            m_sparkParticleSystem = new SparkParticleSystem(p_game, 1000, Vector3.Zero, 3, false);
            m_starParticleSystem = new StarParticleSystem(p_game, 1000, Vector3.Zero, false);
            m_glowParticleSystem = new GlowParticleSystem(p_game, 500, Vector3.Zero, false);
            m_smokeParticleSystem = new SmokeParticleSystem(p_game, 4000, new Vector3(100, 1, 100), true);

            m_gameObjects = new List<GameObject>();
            m_objectsToRemove = new List<GameObject>();
            m_gameLights = new List<GameLight>();
            m_gameSpawnPoints = new List<GameSpawnPoint>();
            m_PowerUpsToSpawn = new List<PowerUpObject>();
            m_CoinsToSpawn = new List<CoinObject>();

            m_gameObjectSelected = false;

            m_debug = p_debug;

            if (!p_debug)
            {
                // The host should take care of the spawnpoints..
                m_remoteGamePlayers = new List<GamePlayer>();
            }
            else
            {
                
                m_wireframe = p_wireframe;
            }

            // Load world file
            loadWorld(p_worldFile);
        }

        public void addRemoteGamePlayer(NetworkGamer p_gamer, int p_cartype, Vector3 p_spawnpos, Vector3 p_spawnrot)
        {
            string t_car_name_id;
            if (p_cartype == 0)
                t_car_name_id = "Car";
            else if (p_cartype == 1)
                t_car_name_id = "AustinMini";
            else
                t_car_name_id = "WAT"; // LOL

            CarObject carObject = new CarObject(Game, this, t_car_name_id,
                                                p_spawnpos,
                                                p_spawnrot,
                                                Vector3.One, false, "RemoteCar", false);

            GamePlayer t_remoteplayer = new GamePlayer(Game, p_gamer, carObject);
            m_remoteGamePlayers.Add(t_remoteplayer);
            Game.Components.Add(t_remoteplayer);
            gameObjects.Add(carObject);
        }

        public void addLocalGamePlayer(int p_cartype, Vector3 p_spawnpos, Vector3 p_spawnrot)
        {
            m_localSpawnPos = p_spawnpos;
            m_localSpawnRot = p_spawnrot;
            string t_car_name_id;
            if (p_cartype == 0)
                t_car_name_id = "Car";
            else if (p_cartype == 1)
                t_car_name_id = "AustinMini";
            else
                t_car_name_id = "WAT"; // LOL

            CarObject carObject = new CarObject(Game, this, t_car_name_id,
                                                p_spawnpos,
                                                p_spawnrot,
                                                Vector3.One, false, "LocalCar", true);
            m_gamePlayer = new GamePlayer(Game, carObject);
            m_gamePlayer.gamer = ((Game1)Game).networkSession.LocalGamers[0];
            Game.Components.Add(m_gamePlayer);
            gameObjects.Add(carObject);
        }

        public void updateRemotePlayer(byte p_id, Vector3 p_pos, Vector3 p_vel, Matrix p_ori)
        {
            foreach (GamePlayer t_player in m_remoteGamePlayers)
            {
                if (t_player.gamer.Id == p_id)
                {
                    t_player.carObject.car.Chassis.Body.MoveTo(p_pos, p_ori);
                    t_player.carObject.car.Chassis.Body.Velocity = p_vel;

                    break;
                }
            }
        }

        // load world from file
        protected void loadWorld(String p_worldFile)
        {
            char[] charSeparators = new char[] {' ', '\t'};

            try
            {
                using (StreamReader sr = new StreamReader(p_worldFile))
                {
                    String line;

                    // read the file line by line
                    while ((line = sr.ReadLine()) != null)
                    {
                        if (line.StartsWith("#")) continue; // Skip comments

                        string[] tokens = line.Split(charSeparators, System.StringSplitOptions.RemoveEmptyEntries);

                        if (tokens.Length == 0) continue; // Skip empty rows

                        if (tokens[0] == "PointLight" || tokens[0] == "SpotLight")
                        {
                            addLight(tokens);
                        }
                        else
                        {
                            addObject(tokens);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("The file could not be read, or wasn't properly formated:");
                Console.WriteLine(e.Message);
            }

            // Add car if we are in debug mode
            if (m_debug)
            {
                CarObject carObject = new CarObject(Game, this, "Car",
                                                m_gameSpawnPoints[0].position,
                                                m_gameSpawnPoints[0].rotation,
                                                Vector3.One, false, "Car", true);
                m_gamePlayer = new GamePlayer(Game, carObject);
                Game.Components.Add(m_gamePlayer);
                gameObjects.Add(carObject);

            }
        }

        // add a spotlight source
        private void addLight(String[] p_tokens)
        {
            GameLight light = null;

            Vector3 lightPosition = new Vector3(
                float.Parse(p_tokens[1], CultureInfo.InvariantCulture.NumberFormat),
                float.Parse(p_tokens[2], CultureInfo.InvariantCulture.NumberFormat),
                float.Parse(p_tokens[3], CultureInfo.InvariantCulture.NumberFormat));

            float lightFalloffStart = float.Parse(p_tokens[4], CultureInfo.InvariantCulture.NumberFormat);
            float lightFalloffEnd = float.Parse(p_tokens[5], CultureInfo.InvariantCulture.NumberFormat);

            Vector3 lighColor = new Vector3(
                float.Parse(p_tokens[6], CultureInfo.InvariantCulture.NumberFormat),
                float.Parse(p_tokens[7], CultureInfo.InvariantCulture.NumberFormat),
                float.Parse(p_tokens[8], CultureInfo.InvariantCulture.NumberFormat));

            if (p_tokens[0] == "PointLight")
            {
                light = new GamePointLight(Game, lightPosition, lightFalloffStart, lightFalloffEnd, lighColor, 256);
            }
            else
            {
                Vector3 lightDirection = new Vector3(
                    float.Parse(p_tokens[9], CultureInfo.InvariantCulture.NumberFormat),
                    float.Parse(p_tokens[10], CultureInfo.InvariantCulture.NumberFormat),
                    float.Parse(p_tokens[11], CultureInfo.InvariantCulture.NumberFormat));

                float lightCutoffStart = float.Parse(p_tokens[12], CultureInfo.InvariantCulture.NumberFormat);
                float lightCutoffEnd = float.Parse(p_tokens[13], CultureInfo.InvariantCulture.NumberFormat);
                float lightCutoffExp = float.Parse(p_tokens[14], CultureInfo.InvariantCulture.NumberFormat);

                light = new GameSpotLight(Game, lightPosition, lightFalloffStart, lightFalloffEnd, lighColor
                    , lightDirection, lightCutoffStart, lightCutoffEnd, lightCutoffExp, 512); // SHADOW
            }

            gameLights.Add(light);
        }

        // load GameObject files
        private void addObject(String[] p_tokens)
        {
            Vector3 goPosition = new Vector3(
                                float.Parse(p_tokens[1], CultureInfo.InvariantCulture.NumberFormat),
                                float.Parse(p_tokens[2], CultureInfo.InvariantCulture.NumberFormat),
                                float.Parse(p_tokens[3], CultureInfo.InvariantCulture.NumberFormat));

            Vector3 goRotation = new Vector3(
                MathHelper.ToRadians(float.Parse(p_tokens[4], CultureInfo.InvariantCulture.NumberFormat)),
                MathHelper.ToRadians(float.Parse(p_tokens[5], CultureInfo.InvariantCulture.NumberFormat)),
                MathHelper.ToRadians(float.Parse(p_tokens[6], CultureInfo.InvariantCulture.NumberFormat)));

            Vector3 goScale = new Vector3(
                float.Parse(p_tokens[7], CultureInfo.InvariantCulture.NumberFormat),
                float.Parse(p_tokens[8], CultureInfo.InvariantCulture.NumberFormat),
                float.Parse(p_tokens[9], CultureInfo.InvariantCulture.NumberFormat));

            bool staticFlag = p_tokens[10] == "1";
            
            String optionalAlias;
            if (p_tokens.Length >= 12)
            {
                optionalAlias = p_tokens[11];
            }
            else
            {
                optionalAlias = "";
            }
            
            String powerUpType;
            if (p_tokens.Length >= 13)
            {
                powerUpType = p_tokens[12];
            }
            else
            {
                powerUpType = "";
            }
            
            Vector3 jumpVelocity = Vector3.One;
            if (p_tokens.Length > 13)
            {
                jumpVelocity = new Vector3(
                                float.Parse(p_tokens[14], CultureInfo.InvariantCulture.NumberFormat),
                                float.Parse(p_tokens[15], CultureInfo.InvariantCulture.NumberFormat),
                                float.Parse(p_tokens[16], CultureInfo.InvariantCulture.NumberFormat));
            }            

            addGameObject(p_tokens[0], goPosition, goRotation, goScale, staticFlag, optionalAlias, powerUpType, jumpVelocity);
        }

        // makes debuging easier
        public virtual void addGameObject(String p_objectType, Vector3 p_goPosition, Vector3 p_goRotation,
            Vector3 p_goScale, bool p_staticFlag, String p_optionalAlias, String p_powerUpType_CoinValue, Vector3 p_jumpVelocity)
        {
            GameObject go = null;

            if (p_objectType == "Car" || p_objectType == "AustinMini")
            {
                go = new CarObject(Game, this, p_objectType, p_goPosition, p_goRotation,
                    p_goScale, p_staticFlag, p_optionalAlias, true);
                gameObjects.Add(go);
            }
            else if (p_objectType == "SpawnPoint")
            {
                m_gameSpawnPoints.Add(new GameSpawnPoint(p_goPosition, p_goRotation));
            }
            else if (p_objectType == "PowerUp")
            {
                go = new PowerUpObject(Game, this, p_objectType, p_goPosition, p_goRotation, p_goScale,
                    p_staticFlag, p_optionalAlias, p_powerUpType_CoinValue);
                gameObjects.Add(go);
            }
            else if (p_objectType == "Jump")
            {
                go = new JumpObject(Game, this, p_objectType, p_goPosition, p_goRotation, p_goScale,
                    p_staticFlag, p_optionalAlias, p_jumpVelocity);
                gameObjects.Add(go);
            }
            else if (p_objectType == "Lloyd_coin" || p_objectType == "Lloyd_coin_cu" || p_objectType == "Lloyd_coin_ag")
            {
                go = new CoinObject(Game, this, p_objectType, p_goPosition, p_goRotation, p_goScale,
                    p_staticFlag, p_optionalAlias, p_powerUpType_CoinValue);
                gameObjects.Add(go);
            }
            else
            {
                if (!m_debug)
                {
                    go = new GameObject(Game, this, p_objectType, p_goPosition, p_goRotation,
                        p_goScale, p_staticFlag, p_optionalAlias);
                }
                else
                {
                    go = new DebugGameObject(Game, this, p_objectType, p_goPosition, p_goRotation,
                    p_goScale, p_staticFlag, p_optionalAlias, m_wireframe);
                }
                gameObjects.Add(go);
            }

        }

        public void markForRemoval(GameObject p_gameObject)
        {
            p_gameObject.alive = false;
            m_objectsToRemove.Add(p_gameObject);
        }

        public void removeGameObjects()
        {
            foreach (GameObject gameObject in m_objectsToRemove)
            {
                gameObject.body.DisableBody();
                ((Game1)Game).physSystem.RemoveBody(gameObject.body);
                m_gameObjects.Remove(gameObject);
                Game.Components.Remove(gameObject);
            }

            m_objectsToRemove.Clear();
        }
        #endregion Constructors and Initialization

        #region Draw
        // draw all GameObjects
        public void draw(GameTime p_gameTime)
        {
            // do not render directly to the screen
            Game.GraphicsDevice.SetRenderTarget(0, m_colorTarget);
            Game.GraphicsDevice.SetRenderTarget(1, m_depthTarget);
            Game.GraphicsDevice.SetRenderTarget(2, m_normalTarget);

            DepthStencilBuffer depthStencilBackup = Game.GraphicsDevice.DepthStencilBuffer;
            Game.GraphicsDevice.DepthStencilBuffer = m_depthStencil;

            Game.GraphicsDevice.Clear(Color.CornflowerBlue);

            // setup lighting for all GameObjects
            foreach (GameObject gameObject in m_gameObjects)
            {
                setupLighting(gameObject);
            }

            // setup render state for blending
            Game.GraphicsDevice.RenderState.BlendFunction = BlendFunction.Add;
            Game.GraphicsDevice.RenderState.DestinationBlend = Blend.One;
            Game.GraphicsDevice.RenderState.SourceBlend = Blend.One;

            // always render fragments at same depth
            Game.GraphicsDevice.RenderState.DepthBufferFunction = CompareFunction.LessEqual;
            Game.GraphicsDevice.RenderState.DepthBufferEnable = true;

            // write to depth buffer, do not blend
            Game.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;
            Game.GraphicsDevice.RenderState.AlphaBlendEnable = false;
            
            // draw ambient pass, setting base color in frame buffer and final depth in depth buffer
            foreach (GameObject gameObject in m_gameObjects)
            {
                gameObject.draw(p_gameTime, GameObject.drawMode.AMBIENT);
            }

            // depths and normals are determined in the ambient pass
            Game.GraphicsDevice.SetRenderTarget(1, null);
            Game.GraphicsDevice.SetRenderTarget(2, null);

            Texture2D depthTex = m_depthTarget.GetTexture();
            Texture2D normalTex = m_normalTarget.GetTexture();
            
            // do not write to depth buffer, use blending
            Game.GraphicsDevice.RenderState.AlphaBlendEnable = true;
            Game.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;
            
            // draw diffuse and specular pass
            foreach (GameObject gameObject in m_gameObjects)
            {
                gameObject.draw(p_gameTime, GameObject.drawMode.LIGHTS);
            }

            // use alpha channel in particle texture to blend particle system with scene
            Game.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
            Game.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;

            // retain the high alpha value so that particles do not get masked
            Game.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = true;
            Game.GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Max;

            // draw the particle systems
            m_sparkParticleSystem.draw(p_gameTime, null);
            m_smokeParticleSystem.draw(p_gameTime, depthTex);
            m_glowParticleSystem.draw(p_gameTime, depthTex);
            m_starParticleSystem.draw(p_gameTime, depthTex);

            Game.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = false;
            
            // mask out the car for motion blur
            if(m_gamePlayer != null)
                m_gamePlayer.carObject.draw(p_gameTime, GameObject.drawMode.MASK);
            
            // get the rendered image
            Game.GraphicsDevice.SetRenderTarget(0, null);
            Texture2D colorTex = m_colorTarget.GetTexture();

            // do not blend or use the depth buffer for post processing
            Game.GraphicsDevice.RenderState.AlphaBlendEnable = false;
            Game.GraphicsDevice.RenderState.DepthBufferEnable = false;

            // Bloom
            if (((Game1)Game).settingGFXBloom)
                colorTex = m_bloomProcessor.process(colorTex);

            // Screen Space Ambient Occlusion
            if (((Game1)Game).settingGFXSSAO)
                colorTex = m_SSAOProcessor.process(colorTex, depthTex, normalTex);

            // Motion Blur
            if (((Game1)Game).settingGFXMotionBlur)
                colorTex = m_motionBlurProcessor.process(colorTex, depthTex);

            // Edge Detection (for the lulz)
            if (((Game1)Game).reverse_powerup)
                colorTex = m_simpleImageProcessor.process(colorTex, "SobelFilter3");


            // restore the depth stencil buffer
            Game.GraphicsDevice.DepthStencilBuffer = depthStencilBackup;

            // draw the final image
            SpriteBatch spriteBatch = new SpriteBatch(Game.GraphicsDevice);
            spriteBatch.Begin();
            spriteBatch.Draw(
                colorTex,
                new Microsoft.Xna.Framework.Rectangle(0, 0,
                    Game.GraphicsDevice.Viewport.Width,
                    Game.GraphicsDevice.Viewport.Height),
                Color.White);
            spriteBatch.End();

            /*
             * TODO: Render player tags above GamePlayers
             */
            SpriteBatch t_spritebatch = new SpriteBatch(Game.GraphicsDevice);
            if (m_remoteGamePlayers != null)
            {
                foreach (GamePlayer t_player in m_remoteGamePlayers)
                {
                    t_player.DrawGamerTag(t_spritebatch);
                }
            }
            //m_gamePlayer.DrawGamerTag(t_spritebatch);
            

            
        }

        // descide what lights to use for the rendering of an object
        public void setupLighting(GameObject gameObject)
        {
            List<GameLight> usedLights = new List<GameLight>();

            foreach (GameLight light in gameLights)
            {
                // use if the object is within the lights reach
                Vector3 lightToObject = gameObject.position - light.position;

                // doesn't work, needs to take more than centre of object into consideration
                if (lightToObject.Length() <= light.falloffEnd)
                {
                    usedLights.Add(light);
                    continue;
                }

                // possibly more complicated stuffs
                usedLights.Add(light); // use all lights for now
            }

            gameObject.usedLights = usedLights;
        }
        #endregion Draw

        public void update(GameTime p_gameTime)
        {
            foreach (GameLight light in m_gameLights)
            {
                light.update(p_gameTime);
            }
            if (m_gamePlayer != null)
            {
                if (m_gamePlayer.carObject.position.Y < -5.0f)
                {
                    m_gamePlayer.carObject.body.MoveTo(m_localSpawnPos, Matrix.CreateFromYawPitchRoll(m_localSpawnRot.Y, m_localSpawnRot.X, m_localSpawnRot.Z));
                }
            }
            // update particle systems
            m_sparkParticleSystem.update(p_gameTime);
            m_starParticleSystem.update(p_gameTime);
            m_glowParticleSystem.update(p_gameTime);
            m_smokeParticleSystem.update(p_gameTime);

            //Spawn PowerUps 30 seconds after they were taken..
            List<PowerUpObject> puToRemoveFromSpawnList = new List<PowerUpObject>();
            List<CoinObject> coinsToRemoveFromSpawnList = new List<CoinObject>();
            foreach (PowerUpObject powerUpObject in m_PowerUpsToSpawn)
            {
                if ((((Game1)Game).gameTime.TotalRealTime - powerUpObject.timeTaken) > new TimeSpan(0, 0, 30))
                {
                    addGameObject("PowerUp", powerUpObject.original_pos, powerUpObject.rotation,
                        powerUpObject.scale, powerUpObject.staticFlag, powerUpObject.alias, powerUpObject.powerUpType, Vector3.One);
                    puToRemoveFromSpawnList.Add(powerUpObject);
                }
            }
            foreach (CoinObject coinObject in m_CoinsToSpawn)
            {
                if ((((Game1)Game).gameTime.TotalRealTime - coinObject.timeTaken) > new TimeSpan(0, 0, 30))
                {
                    addGameObject("Lloyd_coin", coinObject.original_pos, coinObject.rotation, coinObject.scale, coinObject.staticFlag,
                        coinObject.alias, coinObject.value.ToString(), Vector3.One);
                    coinsToRemoveFromSpawnList.Add(coinObject);
                }
            }
            while(puToRemoveFromSpawnList.Count > 0)
            {
                m_PowerUpsToSpawn.Remove(puToRemoveFromSpawnList[0]);
                puToRemoveFromSpawnList.Remove(puToRemoveFromSpawnList[0]);
            }
            while (coinsToRemoveFromSpawnList.Count > 0)
            {
                m_CoinsToSpawn.Remove(coinsToRemoveFromSpawnList[0]);
                coinsToRemoveFromSpawnList.Remove(coinsToRemoveFromSpawnList[0]);
            }

        }
    }
}
